Skip to content

Method: lambda$removePendingReferences$4(NamedResource, ListValueDescriptor)

1: /*
2: * JOPA
3: * Copyright (C) 2024 Czech Technical University in Prague
4: *
5: * This library is free software; you can redistribute it and/or
6: * modify it under the terms of the GNU Lesser General Public
7: * License as published by the Free Software Foundation; either
8: * version 3.0 of the License, or (at your option) any later version.
9: *
10: * This library is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13: * Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public
16: * License along with this library.
17: */
18: package cz.cvut.kbss.jopa.oom;
19:
20: import cz.cvut.kbss.ontodriver.descriptor.ListValueDescriptor;
21: import cz.cvut.kbss.ontodriver.model.Assertion;
22: import cz.cvut.kbss.ontodriver.model.NamedResource;
23: import org.slf4j.Logger;
24: import org.slf4j.LoggerFactory;
25:
26: import java.net.URI;
27: import java.util.*;
28: import java.util.function.Predicate;
29:
30: /**
31: * Used to track references to unpersisted instances during transaction.
32: * <p>
33: * The general rule is that on commit, this registry must be empty.
34: */
35: class PendingReferenceRegistry {
36:
37: private static final Logger LOG = LoggerFactory.getLogger(PendingReferenceRegistry.class);
38:
39: private final Map<Object, Set<PendingAssertion>> pendingAssertions = new IdentityHashMap<>();
40:
41: private Map<Object, Set<PendingListReference>> pendingLists;
42: /**
43: * Counts number of pending items per each list
44: */
45: private Map<ListValueDescriptor, Integer> pendingListItems;
46:
47: /**
48: * Registers a new pending assertion.
49: *
50: * @param owner Subject of the assertion
51: * @param assertion The assertion representation
52: * @param object The value of the assertion. Always an individual identifier
53: * @param context Context into which the assertion will be added
54: */
55: void addPendingAssertion(NamedResource owner, Assertion assertion, Object object, URI context) {
56: assert owner != null;
57: assert assertion != null;
58: assert object != null;
59:
60: final PendingAssertion pa = new PendingAssertion(owner, assertion, context);
61: if (!pendingAssertions.containsKey(object)) {
62: pendingAssertions.put(object, new HashSet<>());
63: }
64: pendingAssertions.get(object).add(pa);
65: }
66:
67: /**
68: * Registers a pending reference to a sequence (simple or referenced).
69: *
70: * @param item The pending (unpersisted) item
71: * @param valueDescriptor Descriptor containing info about list owner, linking property etc.
72: * @param values Values of the sequence
73: */
74: void addPendingListReference(Object item, ListValueDescriptor valueDescriptor, List<?> values) {
75: if (pendingLists == null) {
76: this.pendingLists = new IdentityHashMap<>();
77: this.pendingListItems = new HashMap<>();
78: }
79: pendingLists.putIfAbsent(item, new HashSet<>());
80: pendingLists.get(item).add(new PendingListReference(valueDescriptor, values));
81: pendingListItems.compute(valueDescriptor, (k, v) -> v == null ? 1 : v + 1);
82: }
83:
84: /**
85: * Removes any pending persists with the specified object (value of the assertion).
86: *
87: * @param object Object which is no longer considered pending, so all assertions referencing it should be removed
88: * from this registry
89: */
90: Set<PendingAssertion> removeAndGetPendingAssertionsWith(Object object) {
91: assert object != null;
92: final Set<PendingAssertion> pending = pendingAssertions.remove(object);
93: return pending != null ? pending : Collections.emptySet();
94: }
95:
96: Set<PendingListReference> removeAndGetPendingListReferencesWith(Object object) {
97: assert object != null;
98: final Set<PendingListReference> refs = pendingLists == null ? null : pendingLists.remove(object);
99: if (refs == null) {
100: return Collections.emptySet();
101: }
102: final Iterator<PendingListReference> it = refs.iterator();
103: while (it.hasNext()) {
104: final PendingListReference ref = it.next();
105: assert pendingListItems.get(ref.descriptor) != null;
106: pendingListItems.compute(ref.descriptor, (k, v) -> v - 1);
107: if (pendingListItems.get(ref.descriptor) == 0) {
108: pendingListItems.remove(ref.descriptor);
109: } else {
110: it.remove();
111: }
112: }
113: return refs;
114: }
115:
116: Set<Object> getPendingResources() {
117: final Set<Object> pending = new HashSet<>(pendingAssertions.keySet());
118: if (pendingLists != null) {
119: pending.addAll(pendingLists.keySet());
120: }
121: return pending;
122: }
123:
124: boolean hasPendingResources() {
125: return !pendingAssertions.isEmpty() || pendingLists != null && !pendingLists.isEmpty();
126: }
127:
128: /**
129: * Removes all pending assertions which have the same subject (owner).
130: *
131: * @param subject The subject of assertions to remove
132: */
133: void removePendingReferences(NamedResource subject) {
134: if (LOG.isTraceEnabled()) {
135: LOG.trace("Removing pending assertions for subject {}.", subject);
136: }
137: for (Set<PendingAssertion> pending : pendingAssertions.values()) {
138: pending.removeIf(item -> item.getOwner().equals(subject));
139: }
140: pendingAssertions.entrySet().removeIf(e -> e.getValue().isEmpty());
141: removePendingListReferences(desc -> desc.getListOwner().equals(subject));
142: }
143:
144: private void removePendingListReferences(Predicate<ListValueDescriptor> condition) {
145: if (pendingLists == null) {
146: return;
147: }
148: final Set<ListValueDescriptor> removed = new HashSet<>();
149: for (Set<PendingListReference> pending : pendingLists.values()) {
150: final Iterator<PendingListReference> it = pending.iterator();
151: while (it.hasNext()) {
152: final ListValueDescriptor desc = it.next().descriptor;
153: if (condition.test(desc)) {
154: it.remove();
155: removed.add(desc);
156: }
157: }
158: }
159: pendingLists.entrySet().removeIf(e -> e.getValue().isEmpty());
160: removed.forEach(pendingListItems::remove);
161: }
162:
163: /**
164: * Removes pending references representing the specified assertion about the specified subject.
165: *
166: * @param subject Assertion subject
167: * @param assertion The assertion
168: */
169: void removePendingReferences(NamedResource subject, Assertion assertion) {
170: if (LOG.isTraceEnabled()) {
171: LOG.trace("Removing pending assertions {} for subject {}.", assertion, subject);
172: }
173: for (Set<PendingAssertion> pending : pendingAssertions.values()) {
174: pending.removeIf(item -> item.getOwner().equals(subject) && item.getAssertion().equals(assertion));
175: }
176: pendingAssertions.entrySet().removeIf(e -> e.getValue().isEmpty());
177: removePendingListReferences(
178: desc -> desc.getListOwner().equals(subject) && desc.getListProperty().equals(assertion));
179: }
180:
181: static class PendingListReference {
182: private final ListValueDescriptor descriptor;
183: private final List<?> values;
184:
185: private PendingListReference(ListValueDescriptor descriptor, List<?> values) {
186: this.descriptor = descriptor;
187: this.values = values;
188: }
189:
190: public ListValueDescriptor getDescriptor() {
191: return descriptor;
192: }
193:
194: public List<?> getValues() {
195: return values;
196: }
197: }
198: }